package com.zzjson.redisspringboot;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;

import java.io.Serializable;
import java.util.Locale;
import java.util.Map;

/**
 * @Author 霄池
 * @Date 2022/4/27 10:48 上午
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> implements Serializable {
    private static final long serialVersionUID = -444869657858262777L;

    private static Locale locale = LocaleContextHolder.getLocale();

    private String traceId;
    private boolean success = Boolean.TRUE;
    private String errCode;
    private String errorMsg;
    private Map<String, Object> otherData;
    private T model;

    /**
     * 有error的时候是否忽略当前error,{true: 忽略; false: 不忽略}，默认不忽略
     */
    private boolean ignoreError = false;

    public static <T> Result.ResultBuilder<T> successBuilder() {
        return Result.<T>commonBuilder(ResultCodeEnum.SUCCESS)
            .success(Boolean.TRUE);
    }

    public static <T> Result.ResultBuilder<T> successBuilder(T data) {
        return Result.<T>commonBuilder(ResultCodeEnum.SUCCESS)
            .success(Boolean.TRUE)
            .model(data);
    }

    private static <T> Result.ResultBuilder<T> traceBuilder() {
        return Result.<T>builder().traceId("traceId").success(Boolean.TRUE);
    }

    public static <T> Result.ResultBuilder<T> commonBuilder(ResultCodeInterface resultCode) {
        return Result.<T>traceBuilder()
            .success(Boolean.FALSE)
            .errCode(resultCode.code())
            .errorMsg(resultCode.message());
    }

    public static <E> Result<E> create() {
        return Result.<E>traceBuilder().build();
    }

    public static <E> Result<E> create(E data) {
        return Result.<E>traceBuilder().model(data).build();
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param errCode 错误码
     * @param <T>     泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(String errCode) {
        return fail(errCode, null, false, null);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param errCode     错误码
     * @param ignoreError 有error的时候是否忽略当前error
     * @param <T>         泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(String errCode, boolean ignoreError) {
        return fail(errCode, null, ignoreError, null);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param errCode 错误码
     * @param data    返回的数据
     * @param <T>     泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(String errCode, T data) {
        return fail(errCode, null, false, data);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param errCode     错误码
     * @param ignoreError 有error的时候是否忽略当前error
     * @param data        返回的数据
     * @param <T>         泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(String errCode, boolean ignoreError, T data) {
        return fail(errCode, null, ignoreError, data);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param errCode 错误码
     * @param errMsg  错误信息
     * @param <T>     泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(String errCode, String errMsg) {
        return fail(errCode, errMsg, false, null);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param errCode 错误码
     * @param errMsg  错误信息
     * @param data    返回的数据
     * @param <T>     泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(String errCode, String errMsg, T data) {
        return fail(errCode, errMsg, false, data);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param errCode     错误码
     * @param errMsg      错误信息
     * @param ignoreError 有error的时候是否忽略当前error
     * @param <T>         泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(String errCode, String errMsg, boolean ignoreError) {
        return fail(errCode, errMsg, ignoreError, null);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param errCode     错误码
     * @param errMsg      错误信息
     * @param ignoreError 有error的时候是否忽略当前error
     * @param data        返回的数据
     * @param <T>         泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(String errCode, String errMsg, boolean ignoreError, T data) {
        MessageSource msgSource = SpringUtil.getBean("messageSource", MessageSource.class);
        String errorMsg = msgSource == null ? errMsg : msgSource.getMessage(errCode, null, errMsg, locale);
        return Result.<T>traceBuilder()
            .success(Boolean.FALSE)
            .errCode(errCode)
            .errorMsg(errorMsg)
            .ignoreError(ignoreError)
            .model(data)
            .build();
    }

    /**
     * 通过异常构建失败的响应结果
     * @param ex  异常
     * @param <T> 泛型参数
     * @return 返回值
     */
    public static <T> Result<T> fail(Throwable ex) {
        return fail(ex, null, false, null);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param ex          Throwable异常信息
     * @param ignoreError 有error的时候是否忽略当前error
     * @param <T>         泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(Throwable ex, boolean ignoreError) {
        return fail(ex, null, ignoreError, null);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param ex   Throwable异常信息
     * @param data 返回的数据
     * @param <T>  泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(Throwable ex, T data) {
        return fail(ex, null, false, data);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param ex          Throwable异常信息
     * @param ignoreError 有error的时候是否忽略当前error
     * @param data        返回的数据
     * @param <T>         泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(Throwable ex, boolean ignoreError, T data) {
        return fail(ex, null, ignoreError, data);
    }

    /**
     * 通过异常构建失败的响应结果
     * @param ex    异常
     * @param extra 补充信息
     * @param <T>   泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(Throwable ex, String extra) {
        return fail(ex, extra, false, null);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param ex          Throwable异常信息
     * @param extra       补充信息
     * @param ignoreError 有error的时候是否忽略当前error
     * @param <T>         泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(Throwable ex, String extra, boolean ignoreError) {
        return fail(ex, extra, ignoreError, null);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param ex    Throwable异常信息
     * @param extra 补充信息
     * @param data  返回的数据
     * @param <T>   泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(Throwable ex, String extra, T data) {
        return fail(ex, extra, false, data);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param ex          Throwable异常信息
     * @param extra       补充信息
     * @param ignoreError 有error的时候是否忽略当前error
     * @param data        返回的数据
     * @param <T>         泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(Throwable ex, String extra, boolean ignoreError, T data) {
       /* String errorCode = (ex instanceof AlloyException) ? ((AlloyException)ex).getErrorCode()
            : AlloyErrorCode.ALLOY_UNKNOWN_ERROR.code();
        String errorMsg = Objects.nonNull(ex) ? ResultUtil.getSimpleMessageOfThrow(ex)
            : AlloyErrorCode.ALLOY_UNKNOWN_ERROR.message();
        if (StringUtils.isNotBlank(extra)) {
            errorMsg = String.format("%s,%s", errorMsg, extra);
        }*/
        return fail("errorCode", "errorMsg", ignoreError, data);
    }

    /**
     * 通过指定错误码构建失败的响应结果
     * @param resultCode 错误码
     * @param <T>        泛型参数
     * @return 返回值
     */
    public static <T> Result<T> fail(ResultCodeInterface resultCode) {
        return Result.fail(resultCode, null, false, null);
    }

    /**
     * 通过指定错误码构建失败的响应结果
     * @param resultCode  错误码
     * @param ignoreError 有error的时候是否忽略当前error
     * @param <T>         泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(ResultCodeInterface resultCode, boolean ignoreError) {
        return Result.fail(resultCode, null, ignoreError, null);
    }

    /**
     * 通过指定错误码构建失败的响应结果
     * @param resultCode 错误码
     * @param data       返回的数据
     * @param <T>        泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(ResultCodeInterface resultCode, T data) {
        return Result.fail(resultCode, null, false, data);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param resultCode  错误码
     * @param ignoreError 有error的时候是否忽略当前error
     * @param data        返回的数据
     * @param <T>         泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(ResultCodeInterface resultCode, boolean ignoreError, T data) {
        return Result.fail(resultCode, null, ignoreError, data);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param resultCode 错误码
     * @param extra      补充信息
     * @param <T>        泛型参数
     * @return 返回值
     */
    public static <T> Result<T> fail(ResultCodeInterface resultCode, String extra) {
        return Result.fail(resultCode, extra, false, null);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param resultCode  错误码
     * @param extra       补充信息
     * @param ignoreError 有error的时候是否忽略当前error
     * @param <T>         泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(ResultCodeInterface resultCode, String extra, boolean ignoreError) {
        return Result.fail(resultCode, extra, ignoreError, null);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param resultCode 错误码
     * @param extra      补充信息
     * @param data       返回的数据
     * @param <T>        泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(ResultCodeInterface resultCode, String extra, T data) {
        return Result.fail(resultCode, extra, false, data);
    }

    /**
     * 通过指定错误码和补充信息构建失败的响应结果
     * @param resultCode  错误码
     * @param extra       补充信息
     * @param ignoreError 有error的时候是否忽略当前error
     * @param data        返回的数据
     * @param <T>         泛型参数
     * @return Result
     */
    public static <T> Result<T> fail(ResultCodeInterface resultCode, String extra, boolean ignoreError, T data) {
      /*  MessageSource msgSource = SpringUtil.getBean("messageSource", MessageSource.class);
        String extraErrorMsg = StringUtils.trimToEmpty(resultCode.message());
        //拼接补充信息
        if (StringUtils.isNotBlank(extra)) {
            extraErrorMsg = String.format("%s,%s", extraErrorMsg, extra);
        }
        //本地化处理
        if (msgSource != null) {
            extraErrorMsg = msgSource.getMessage(resultCode.code(), null, extraErrorMsg, locale);
        }
        return Result.<T>traceBuilder()
            .success(Boolean.FALSE)
            .errCode(resultCode.code())
            .errorMsg(extraErrorMsg)
            .ignoreError(ignoreError)
            .model(data)
            .build();*/
        return Result.<T>traceBuilder().model(data).build();
    }

    /**
     * for mtop
     */
    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    /**
     * for mtop
     */
    public T getModel() {
        return model;
    }

    public void setModel(T model) {
        this.model = model;
    }

    public String getErrCode() {
        return errCode;
    }

    public void setErrCode(String errCode) {
        this.errCode = errCode;
    }

    /**
     * for mtop
     */
    public String getMsgCode() {
        return errCode;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

    /**
     * for mtop
     */
    public String getMsgInfo() {
        return errorMsg;
    }

    public void setOtherData(Map<String, Object> otherData) {
        this.otherData = otherData;
    }

    public Object getOtherData(String k) {
        if (null == otherData) {
            return null;
        }
        return otherData.get(k);
    }

 /*   public Result<T> addOtherData(String k, Object v) {
        if (null == otherData) {
            otherData = Maps.newHashMap();
        }
        otherData.put(k, v);
        return this;
    }*/
}